/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-20
 * Time: 04:02
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Windows.Forms;

using Labb4.Pooman.Cards;
using Labb4.Rules;

namespace Labb4.Pooman.Players
{
	/// <summary>
	/// An ai for playing phase 1, with getting cards as high as possible as agenda
	/// </summary>
	public class AiGameStatePhase1Value : AiGameState
	{
		#region members
		
		/// <summary>
		/// The minimum value needed on the table to try and take the cards
		/// </summary>
		private readonly int						m_MinimumValueToAttemptTake;
		/// <summary>
		/// Holds the system by which the cards are calculated into an aiSum
		/// </summary>
		private readonly Dictionary<int, int>		m_Points;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		public AiGameStatePhase1Value() :
			base()
		{
			//This is the minimum value needed in an aiSum for this ai to try and take the cards
			m_MinimumValueToAttemptTake = 1;
			m_Points = new Dictionary<int, int>();
			
			//This is the table of aiSum values
			//Left row is the value of the card, right row is the aiSum value of a card with that card value
			m_Points.Add(2, -6);
			m_Points.Add(3, -5);
			m_Points.Add(4, -4);
			m_Points.Add(5, -3);
			m_Points.Add(6, -2);
			m_Points.Add(7, -1);
			m_Points.Add(8, 0);
			m_Points.Add(9, 0);
			m_Points.Add(10, 0);
			m_Points.Add(11, 2);
			m_Points.Add(12, 4);
			m_Points.Add(13, 6);
			m_Points.Add(14, 8);
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// This method chooses the cards the AI wants to play.
		/// 
		/// This perticular AI selects cards based on how high the cards it stands
		/// to win are.
		/// </summary>
		/// <param name="player">A reference to the player making the move</param>
		public override void SelectCardsAccordingToPhase(Player player)
		{
			if(player.CurrentHand.Cards.Count > 0)
			{
				//are the cards on the table "good" enough (i.e. high enough in value)
				//while calculating this, we'll also find the value of the highest card on the table
				int highestCardOnTable = 0;
				
				try
				{
					highestCardOnTable = PoomanRules.Instance.CurrentRound.GetHighestCardInPlay(null).ValueOfCard;
				}
				catch(Exception)
				{
				}
				
				int aiSum = 0;
				
				foreach(CardPile itPile in m_GameTable.CardsOnTable)
				{
					foreach(Card itCard in itPile)
					{
						aiSum += m_Points[itCard.ValueOfCard];
					}
				}
				
				//now, we have found out which the highest card on the table is
				//this way, we know if we can top it / give it away
				
				//now... is it possible for us to take these cards? or at least to fight for them?
				int highestCardOnHand = HighestCardvalueInPile(player.CurrentHand.Cards);
				
				if(highestCardOnHand >= highestCardOnTable)
				{
					//ok, now, we can take these cards if we want to.. but do we want them?
					//of course, we have to factor in the card we will get while taking them.. our highest
					//by the way, are there more than one of this card?
					int numberOfTheHighestCardOnHand = 0;
					
					foreach(Card it in player.CurrentHand.Cards)
					{
						if(it.ValueOfCard == highestCardOnHand)
						{
							numberOfTheHighestCardOnHand++;
						}
					}
					
					for(int i = 0; i < numberOfTheHighestCardOnHand; i++)
					{
						aiSum += m_Points[highestCardOnHand];
					}
					
					if(aiSum >= m_MinimumValueToAttemptTake)
					{
						//so, we've decided we're gonna take these cards.. let's now select the card(s) to play
						foreach(Card it in player.CurrentHand.Cards)
						{
							if(it.ValueOfCard == highestCardOnHand)
							{
								it.SelectCard(true);
							}
						}
					}
					else
					{
						//aha.. these cards are not worthy! can we escape them?
						//let's find the highest card that is just below the highest card on the table
						//but is not a card that we would consider valuable
						
						//let's start with finding the lowest card on hand
						Card lowestCardOnHand = LowestCardInPile(player.CurrentHand.Cards);
						
						//now, can we give these cards away? or at least "fight" for giving them away?
						if(lowestCardOnHand.ValueOfCard <= highestCardOnTable)
						{
							//yes! we can give it away, let's try to give away as high a card as possible
							//without giving away a "good" card of course ;)
							
							Card giveAwayCard = HighestPointlessCardBelowLimit(player.CurrentHand.Cards, highestCardOnTable);
							
							//I proudly give you: our give away card! let's select it for play
							giveAwayCard.SelectCard(true);
						}
						else
						{
							//oh no!!!! there is no escape!!!!!! ok, minimize damage, use the highest card..
							//if this card has any points to it, and we have more than one of it, we will play them all
							bool playAll = false;
							
							if(m_Points[highestCardOnHand] > 0)
							{
								playAll = true;
							}
							
							bool played = false;
							
							foreach(Card it in player.CurrentHand.Cards)
							{
								if(it.ValueOfCard == highestCardOnHand)
								{
									if(!played)
									{
										it.SelectCard(true);
										
										if(!playAll)
										{
											played = true;
										}
									}
								}
							}
						}
					}
				}
				else
				{
					//oh no.. we can't take these cards..
					//play as high a card as possible, without using cards that are points..
					bool allCardsHavePoints = true;
					
					foreach(Card it in player.CurrentHand.Cards)
					{
						if(m_Points[it.ValueOfCard] < 1)
						{
							allCardsHavePoints = false;
						}
					}
					
					Card lowestCardOnHand = LowestCardInPile(player.CurrentHand.Cards);
					
					if(allCardsHavePoints)
					{
						//ouch.. we only have good cards on hand, and appearantly none of them
						//are high enough to get all the good stuff on the table..
						//let's play the lowest of our cards!
						
						lowestCardOnHand.SelectCard(true);
					}
					else
					{
						//alright.. we can't get the cards on the table, but at least we're not loosing any
						//points on hand over that
						
						//it's time to find the highest, pointless card
						Card giveAwayCard = HighestPointlessCardBelowLimit(player.CurrentHand.Cards, highestCardOnTable);
						giveAwayCard.SelectCard(true);
					}
				}
				
				//now, if no card is selected, then we have a problem with bad code :(
				if(player.CurrentHand.SelectedCards() == 0)
				{
					MessageBox.Show("Oops... ValueAI falied to select cards.. Defaulting to first card on hand", "ValueAI error");
					player.CurrentHand.Cards[0].SelectCard(true);
				}
				
				player.Controler.PressedPlay = true;
			}
			else
			{
				//This code segment is never reached anymore, so it can soon be removed
				MessageBox.Show("Phase 1 seems to be over.. Last player was SuitAI");
				PoomanRules.Instance.MainPoo.SwitchPhase();
			}
		}
		
		public override Labb4.Pooman.Players.Player.Evaluation EvaluateWonCardsPhase1(Player player, CardPile cards)
		{
			return player.EvaluateBasedOnValue(cards);
		}
		
		#endregion
		
		#region private methods
		
		/// <summary>
		/// Finds the highest card below a certain limit in a CardPile.
		/// Primarily searches for cards with 0 points or less (see <see cref="Points">Dictionary Points</see>)
		/// If there is no card with 0 points or less below the set limit, the lowest card is returned
		/// If there is no card below the set limit, the lowest card is returned
		/// </summary>
		/// <param name="cardsOnHand">The CardPile to look in</param>
		/// <param name="limit">The limit below which to find a Card (by Rank)</param>
		/// <returns>The highest Card - below the set limit - found in the given CardPile</returns>
		private Card HighestPointlessCardBelowLimit(CardPile cardsOnHand, int limit)
		{
			Card highestPointless = LowestCardInPile(cardsOnHand);
			
			foreach(Card it in cardsOnHand)
			{
				if((it.ValueOfCard > highestPointless.ValueOfCard) &&
				   (it.ValueOfCard < limit) &&
				   (m_Points[it.ValueOfCard] < 1))
				{
					highestPointless = it;
				}
			}
			
			return highestPointless;
		}
		
		#endregion
	}
}
